/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package z.h.w.jar.kit.method;

import java.awt.Color;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import z.h.w.jar.arithmetic.Sort;
import z.h.w.jar.arithmetic.method.SortMethodApi;

/**
 *
 * @author EnzoZhong
 * @date 2011-12-8
 */
public class Roll {

      /**
       *
       */
      final private static String A2Z = range ( 'a' , 'z' );

      /**
       * 输出从字符min到字符max之间的所有字符
       *
       * @param min
       * @param max
       * @return
       */
      public static synchronized String range ( Character min , Character max ) {
            StringBuffer sb = new StringBuffer ();
            Deque<Character> deque = minMax ( min , max );
            min = deque.getFirst ();
            max = deque.getLast ();
            for ( int x = min ; x <= max ; x ++ ) {
                  sb.append ( ( char ) x );
            }
            return sb.toString ();
      }

      /**
       *
       * @param min param max param random
       * <p/>
       * @param max
       * @param random
       *
       * @return
       */
      public static synchronized Double range ( Double min , Double max , Random random ) {
            Deque<Double> deque = minMax ( min , max );
            min = deque.getFirst ();
            max = deque.getLast ();
            return ( rollDouble ( random ) * 10000 ) % ( max - min ) + min;
      }

      /**
       *
       * @param min param max
       * <p/>
       * @param max
       *
       * @return
       */
      public static synchronized Double range ( Double min , Double max ) {
            Deque<Double> deque = minMax ( min , max );
            min = deque.getFirst ();
            max = deque.getLast ();
            return ( rollDouble () * 10000 ) % ( max - min ) + min;
      }

      public static synchronized Double range ( Double min , Double max , String regex ) {
            DecimalFormat decimalFormat = new DecimalFormat ( regex );
            String string = decimalFormat.format ( range ( min , max ) );
            return Double.parseDouble ( string );
      }

      /**
       *
       * @param min param max param random
       * <p/>
       * @param max
       * @param random
       *
       * @return
       */
      public static synchronized Integer range ( Integer min , Integer max , Random random ) {
            return range ( min.doubleValue () , max.doubleValue () , random ).intValue ();
      }

      /**
       *
       * @param min param max
       * <p/>
       * @param max
       *
       * @return
       */
      public static synchronized Integer range ( Integer min , Integer max ) {
            return range ( min.doubleValue () , max.doubleValue () ).intValue ();
      }

      /**
       *
       * @param max param random
       * <p/>
       * @param random
       *
       * @return
       */
      public static synchronized Integer range ( Integer max , Random random ) {
            return range ( 0 , max , random );
      }

      /**
       *
       * @param max < p/>
       * <p/>
       * @return
       */
      public static synchronized Integer range ( Integer max ) {
            return range ( 0 , max );
      }

      /**
       *
       * @param min param max param random
       * <p/>
       * @param max
       * @param random
       *
       * @return
       */
      public static synchronized Long range ( Long min , Long max , Random random ) {
            return range ( min.doubleValue () , max.doubleValue () , random ).longValue ();
      }

      /**
       *
       * @return
       */
      public static synchronized Double rollDouble () {
            return rollDouble ( new Random () );
      }

      /**
       *
       * @param len < p/>
       * <p/>
       * @return
       */
      public static synchronized Integer rollInteger ( Integer len ) {
            if ( len >= 10 ) {
                  len = 9;
            }
            Integer[] one2Nine = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 };
            Integer[] zero2Nine = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 };
            StringBuffer sb = new StringBuffer ();
            sb.append ( Roll.roll ( one2Nine ) );

            for ( int x = 0 ; x < len - 1 ; x ++ ) {
                  sb.append ( Roll.roll ( zero2Nine ) );
            }
            return Integer.parseInt ( sb.toString () );
      }

      /**
       *
       * @param len < p/>
       * <p/>
       * @return
       */
      public static synchronized Long rollLong ( Integer len ) {
            if ( len >= 19 ) {
                  len = 18;
            }
            Integer[] one2Nine = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 };
            Integer[] zero2Nine = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 };
            StringBuffer sb = new StringBuffer ();
            sb.append ( Roll.roll ( one2Nine ) );

            for ( int x = 0 ; x < len - 1 ; x ++ ) {
                  sb.append ( Roll.roll ( zero2Nine ) );
            }
            return Long.parseLong ( sb.toString () );
      }

      /**
       *
       * @param random < p/>
       * <p/>
       * @return
       */
      public static synchronized Double rollDouble ( Random random ) {
            return random.nextDouble ();
      }

      /**
       *
       * @return
       */
      public static synchronized Long rollLong () {
            return rollLong ( new Random () );
      }

      /**
       *
       * @param random < p/>
       * <p/>
       * @return
       */
      public static synchronized Long rollLong ( Random random ) {
            return random.nextLong ();
      }

      /**
       *
       * @return
       */
      public static synchronized Color rollColor () {
            return new Color ( Roll.range ( 254 ) , Roll.range ( 254 ) , Roll.range ( 254 ) );
      }

      /**
       *
       * @param size < p/>
       * <p/>
       * @return
       */
      public static synchronized Color[] rollColor ( Integer size ) {
            List<Color> re = new ArrayList<> ( 10 );
            for ( int x = 0 ; x < size ; x ++ ) {
                  re.add ( rollColor () );
            }
            return To.list2Array ( re );
      }

      /**
       *
       * @param r param g param b
       * <p/>
       * @param g
       * @param b
       *
       * @return
       */
      public static synchronized Color rollColor ( Integer r , Integer g , Integer b ) {
            return new Color ( Roll.range ( r ) , Roll.range ( g ) , Roll.range ( b ) );
      }

      /**
       * 随机a到z的字符串
       * <p/>
       * @return
       */
      public static synchronized String rollString () {
            StringBuffer sb = new StringBuffer ();
            int len = Roll.range ( 20 );
            for ( int x = 0 ; x < len ; x ++ ) {
                  sb.append ( A2Z.charAt ( range ( A2Z.length () ) ) );
            }
            return sb.toString ();
      }

      /**
       * 指定长度的随机字符串
       * <p/>
       * @param len < p/>
       * <p/>
       * @return
       */
      public static synchronized String rollString ( Integer len ) {
            StringBuffer sb = new StringBuffer ();
            for ( int x = 0 ; x < len ; x ++ ) {
                  sb.append ( A2Z.charAt ( range ( A2Z.length () ) ) );
            }
            return sb.toString ();
      }

      /**
       *
       * @param base param len
       * <p/>
       * @param len
       *
       * @return
       */
      public static synchronized String rollString ( String base , Integer len ) {
            StringBuffer sb = new StringBuffer ( base );
            for ( int x = 0 ; x < len ; x ++ ) {
                  sb.append ( A2Z.charAt ( range ( A2Z.length () ) ) );
            }
            return sb.toString ();
      }

      /**
       * 随机pop出List中的元素
       * <p/>
       * @param <T> param list
       * <p/>
       * @param list < p/>
       * <p/>
       * @return
       */
      public static synchronized <T> T roll ( List<T> list ) {
            return list.get ( range ( list.size () ) );
      }

      /**
       * 随机pop出List中的元素
       * <p/>
       * @param <T> < p/>
       * <p/>
       * @param array < p/>
       * <p/>
       * @return
       */
      public static synchronized <T> T roll ( T[] array ) {
            return array[range ( array.length )];
      }

      /**
       * 随机pop出map中的key值
       * <p/>
       * @param <Key> param <Val> param map
       * <p/>
       * @param <Val> map
       * <p/>
       * @param map
       *
       * @return
       */
      public static synchronized <Key , Val> Key roll ( Map<Key , Val> map ) {
            Set<Key> set = map.keySet ();
            return roll ( To.set2List ( set ) );
      }

      private static synchronized <Type extends Comparable<? super Type>> Deque<Type> minMax ( Type... type ) {
            Deque<Type> queue = new LinkedList<> ();
            type = Sort.sort ( type , SortMethodApi.SHELL );
            queue.addAll ( Arrays.asList ( type ) );
            return queue;
      }

}
